package com.itheima.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.itheima.bean.Dish;
import com.itheima.bean.DishFlavor;
import com.itheima.dao.DishDao;
import com.itheima.dao.DishFlavorDao;
import com.itheima.dto.DishDto;
import com.itheima.exception.CustomException;
import com.itheima.service.DishService;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.Arrays;
import java.util.List;

@Service
public class DishServiceImpl extends ServiceImpl<DishDao, Dish> implements DishService {


	@Autowired
	private DishFlavorDao dishFlavorDao;

	@Override
	public void saveWithFlavor(DishDto dishDto) {

		//0.判断菜品名称是否存在  存在：抛出自定义异常提示
		LambdaQueryWrapper<Dish> wrapper = new LambdaQueryWrapper<>();
		wrapper.eq(Dish::getName, dishDto.getName());
		int count = this.count(wrapper);
		if (count > 0) {
			throw new CustomException("当前菜品【" + dishDto.getName() + "】已经存在！");
		}

		//1.保存菜品基本信息到菜品表    dish
		// 这里使用MyBatisPlus提供的service通用方法即可 dishDto是Dish子类对象  新增的时候插入数据到dish表 只会拿DishDto中继承Dish类的那些属性使用
		this.save(dishDto);

		//2.保存菜品口味信息到菜品口味表 dish_flavor
		//1.获取当前新增菜品口味列表数据   一个菜品下可以有多个口味设置
		List<DishFlavor> flavors = dishDto.getFlavors();

		//2.遍历当前菜品口味信息列表数据  设置每条口味信息关联当前新增菜品id  保存到dish_flavor表中
		//a：获取当前新增菜品id   原因：因为前面已经将菜品基本信息保存到菜品dish表中 MyBatisPlus中保存数据时会自动返回主键数据封装到原有对象属性中
		Long dishId = dishDto.getId();

        /*
            回顾lambda表达式：
                书写格式：()->{}
                    ()中放方法参数   也就是Stream流中的元素   {}:方法体 重新抽象方法
                省略规则:
                    1.小括号中如果只有一个参数 可以省略小括号
                    2.大括号中如果只有一句代码 这可以省略大括号以及return
         */
		//高级玩法：Stream流 高大上
		//b.遍历当前菜品口味信息列表数据   这里不需要非空判断
		flavors.stream().forEach((flavor) -> {
			//c：设置每条口味信息关联当前新增菜品id
			flavor.setDishId(dishId);

			//d：保存到dish_flavor表中
			dishFlavorDao.insert(flavor);
		});

        /* for循环遍历数据   low
        //b.遍历当前菜品口味信息列表数据
        if(flavors!=null && flavors.size()>0){
            for (DishFlavor flavor : flavors) {
                //c：设置每条口味信息关联当前新增菜品id
                flavor.setDishId(dishId);

                //d：保存到dish_flavor表中
                dishFlavorDao.insert(flavor);
            }
        }
        */

	}

	@Override
	public DishDto findById(Long id) {
		DishDto dishDto = new DishDto();

		//1.根据菜品id去菜品dish表中查询菜品基本信息封装到DishDto对象中
        /*
            this表示当前类对象
                this.getById()：调用当前类中的非静态方法
                    getById方法是由MyBatisPlus在IService中提供的通用方法 已经封装好的 因为我们的Service实现类继承了ServiceImpl实现了IService
                    this在使用时 可以省略
         */
		Dish dish = this.getById(id);
		BeanUtils.copyProperties(dish, dishDto);

		//2.根据菜品id去菜品口味表中查询菜品口味信息封装到DishDto对象中
		LambdaQueryWrapper<DishFlavor> wrapper = new LambdaQueryWrapper<>();
		wrapper.eq(DishFlavor::getDishId, id);
		List<DishFlavor> flavors = dishFlavorDao.selectList(wrapper);
		dishDto.setFlavors(flavors);

		//3.返回DishDto
		return dishDto;
	}

	@Override
	public void updateWithFlavor(DishDto dishDto) {
		//1.判断修改后的菜品名称和dish表中其他的菜品名称不重复
		LambdaQueryWrapper<Dish> wrapper1 = new LambdaQueryWrapper<>();
		wrapper1.eq(Dish::getName, dishDto.getName());
		wrapper1.ne(Dish::getId, dishDto.getId());       //不是自己
		int count = this.count(wrapper1);
		if (count > 0) {
			throw new CustomException("当前菜品名称【" + dishDto.getName() + "】已经存在！");
		}

		//2.将修改后的菜品基本信息保存到菜品表dish中
		this.updateById(dishDto);

		//3.删除当前菜品原有的口味信息  根据菜品id去菜品口味dish_flavor表中删除
		//获取当前菜品id
		Long dishId = dishDto.getId();
		LambdaQueryWrapper<DishFlavor> wrapper2 = new LambdaQueryWrapper<>();
		wrapper2.eq(DishFlavor::getDishId, dishId);
		dishFlavorDao.delete(wrapper2);     // delete from dish_flavor where dish_id = xxx

		//4.将修改后的菜品口味信息保存到菜品口味表dish_flavor中，关联菜品id
		//a.获取当前菜品修改后的口味信息列表
		List<DishFlavor> flavors = dishDto.getFlavors();

		//b.遍历当前菜品口味信息列表数据   这里不需要非空判断
		flavors.stream().forEach((flavor) -> {
            /*
                如果前面是使用物理删除，则可以不需要设置为null 原因是我们下面执行的是insert新增 不能插入两条数据使用相同的id
                当使用逻辑删除时 就必须设置新插入的菜品口味信息id为null  否则会报主键重复异常
             */
			//c1：设置每条口味信息的id为null
			flavor.setId(null);

			//c2：设置每条口味信息关联当前修改菜品id
			flavor.setDishId(dishId);

			//d：保存到dish_flavor表中
			dishFlavorDao.insert(flavor);
		});
	}

	//停售启售|批量停售启售
	@Override
	public void changeStatusByIds(Long[] ids, Integer status) {
		// 获取当前id菜品
		List<Dish> dishes = this.listByIds(Arrays.asList(ids));
		for (Dish dish : dishes) {
			// 将status放入到当前菜品中
			dish.setStatus(status);
			// 传到数据库
			boolean flag = this.saveOrUpdate(dish);
			if (!flag) {
				throw new CustomException("修改" + dish.getName() + "失败");
			}
		}
	}

	//根据菜品id删除|批量删除
	@Override
	public boolean deleteByIds(Long[] ids) {
		//1.非空判断
		if (ids == null || ids.length == 0) {
			throw new CustomException("请选择要删除的菜品");
		}

		//2.判断是否关联启售中
		List<Dish> dishes = this.listByIds(Arrays.asList(ids));
		LambdaQueryWrapper<Dish> wrapper = new LambdaQueryWrapper<>();
		for (Dish dish : dishes) {
			if (dish.getStatus() == 1) {
				throw new CustomException("当前菜品[" + dish.getName() + "]正处于起售状态,不能删除");
			}
			//3.判断是否关联了套餐
			wrapper.eq(Dish::getCategoryId, dish.getId());
			int count = this.count(wrapper);
			if (count > 0) {
				throw new CustomException("该菜品已关联套餐");
			}
		}

		//4.根据id删除套餐表中setmeal_dish中套餐菜品基本信息数据
		LambdaQueryWrapper<DishFlavor> wrapper1 = new LambdaQueryWrapper<>();
		for (Long id : ids) {
			// 先根据id查询到口味表
			wrapper1.eq(DishFlavor::getDishId, id);
			// 判断该id是否在口味表中
			int count = dishFlavorDao.selectCount(wrapper1);
			if (count > 0) {
				// 若有则进行删除
				dishFlavorDao.delete(wrapper1);
			}
		}

		//5.执行删除操作
		boolean flag = this.removeByIds(Arrays.asList(ids));
		return flag;
	}

}
